[org 0x7c00]

; screen mode = text, then clear it
mov ax,3
int 0x10

; 初始化段寄存器
mov ax,0
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0x7c00

; mov ax,0xb800
; mov ds,ax
; mov byte [0],'H'
mov si, booting
call print

mov edi,0x1000 ;读取目标内存
mov ecx,2 ;起始扇区
mov bl,4 ;扇区数量
call read_disk
cmp word [0x1000],0x55aa
jnz error

jmp 0:0x1002

; 阻塞程序
jmp $

read_disk:
    ;设置读写扇区的数量
    mov dx,0x1f2
    mov al,bl
    out dx,al

    inc dx ;0x1f3
    mov al,cl
    out dx,al

    inc dx ;0x1f4
    shr ecx,8
    mov al,cl
    out dx,al

    inc dx ;0x1f5
    shr ecx,8
    mov al,cl
    out dx,al

    inc dx ;0x1f6
    shr ecx,8
    and cl,0b1111 ; 将高四位置为0
    mov al,0b1110_0000
    or al,cl
    out dx,al

    inc dx; 0x1f7
    mov al,0x20 ;读硬盘
    out dx,al

    xor ecx,ecx ;ecx 清空的最好方式，比mov ecx,0快
    mov cl,bl ;得到读写扇区的数量

    .read:
        push cx;保存cx
        call .waits ;等待数据准备完毕
        call .reads ;读取一个扇区
        pop cx;恢复cx
        loop .read

    ret
    .waits:
        mov dx,0x1f7
        .check:
            in al,dx
            jmp $+2 ;直接跳转到下一行
            jmp $+2 ; 一点点延迟
            jmp $+2
            and al,0b1000_1000
            cmp al,0b0000_1000
            jnz .check
        ret
    .reads:
        mov dx,0x1f0
        mov cx,256;一个扇区256字
        .readw:
            in ax,dx
            jmp $+2 ;直接跳转到下一行
            jmp $+2 ; 一点点延迟
            jmp $+2
            mov [edi],ax
            add edi,2
            loop .readw
        ret

write_disk:
    ;设置读写扇区的数量
    mov dx,0x1f2
    mov al,bl
    out dx,al

    inc dx ;0x1f3
    mov al,cl
    out dx,al

    inc dx ;0x1f4
    shr ecx,8
    mov al,cl
    out dx,al

    inc dx ;0x1f5
    shr ecx,8
    mov al,cl
    out dx,al

    inc dx ;0x1f6
    shr ecx,8
    and cl,0b1111 ; 将高四位置为0
    mov al,0b1110_0000
    or al,cl
    out dx,al

    inc dx; 0x1f7
    mov al,0x30 ;写硬盘 <
    out dx,al

    xor ecx,ecx ;ecx 清空的最好方式，比mov ecx,0快
    mov cl,bl ;得到读写扇区的数量

    .write:
        push cx;保存cx
        call .writes ;写一个扇区
        call .waits ;等待硬盘繁忙结束
        pop cx;恢复cx
        loop .write

    ret
    .waits:
        mov dx,0x1f7
        .check:
            in al,dx
            jmp $+2 ;直接跳转到下一行
            jmp $+2 ; 一点点延迟
            jmp $+2
            and al,0b1000_0000
            cmp al,0b0000_0000
            jnz .check
        ret
    .writes:
        mov dx,0x1f0
        mov cx,256;一个扇区256字
        .writew:
            mov ax,[edi]
            out dx,ax
            jmp $+2 ;直接跳转到下一行
            jmp $+2 ; 一点点延迟
            jmp $+2
            add edi,2
            loop .writew
        ret


; print 函数
print:
    mov ah,0x0e
.next:
    mov al,[si]
    cmp al,0
    jz .done
    int 0x10
    inc si
    jmp .next
.done:
    ret

booting:
    db "[INFO] Booting TobyOS...",10,13,0 ; 10是ascii的\n，13是ascii的\r
error:
    mov si,.msg
    call print
    hlt ;让cpu停止
    jmp $ ;错误就直接死机
    .msg db "[Error] Boot Failed",10,13,0
; 填充到510字节，记上下面0x55,0xaa就512个字节
times 510 - ($ - $$) db 0

; BIOS需要主引导扇区末尾两个字节是0x55,0xaa
;dw 0x55aa
db 0x55,0xaa